#include "Http/UserAction.h"
#include "Core/SafeLock.h"
#include "Core/GlobalSet.h"
#include "Zip/zip.h"

BEGIN_GLSX_NAMESPACE

#define GROW_SIZE (64 * 1024)

typedef struct _tagUserAction
{
	mutable bool m_bExit;
	DWORD m_dwThreadId;
	char* m_pUserActionData;
	int m_nBufferSize;
	int m_nDataSize;

	UINT_PTR  nIDTimerEvent;
	HANDLE m_hFlowThread;
	HANDLE m_hWaitEvent;
	CRITICAL_SECTION m_cs;

} UserAction;

static UserAction* g_pUserAction = NULL;

static DWORD SubmitFlowThread(LPVOID pUserData)
{
	printf("Enter Submit Thread\n");
	while(WaitForSingleObject(g_pUserAction->m_hWaitEvent, INFINITE) == WAIT_OBJECT_0)
	{
		::EnterCriticalSection(&g_pUserAction->m_cs);

		if (g_pUserAction->m_pUserActionData && g_pUserAction->m_nDataSize > 0)
		{
			free(g_pUserAction->m_pUserActionData);
			g_pUserAction->m_pUserActionData = NULL;
			g_pUserAction->m_nDataSize = 0;
			g_pUserAction->m_nBufferSize = 0;
		}

		::LeaveCriticalSection(&g_pUserAction->m_cs);

		printf("Begin Submit user action: %d\n", 0);

		if (g_pUserAction->m_nDataSize > 0){
		}else{
			printf("user data size is 0, no need to submit\n");
		}

		printf("End submit user action\n");

		if (g_pUserAction->m_bExit)
		{
			break;
		}
	}
	return 0;
}

static VOID CALLBACK TimerProc(HWND hwnd,UINT uMsg, UINT_PTR idEvent,DWORD dwTime)
{
	if (g_pUserAction->m_hFlowThread == NULL || g_pUserAction->m_nDataSize <= 0)
	{
		return;
	}

	printf("Begin Timer Submit user action\n");

	SetEvent(g_pUserAction->m_hWaitEvent);
}



GlsxCommon_API int InitUserAction()
{
	if (g_pUserAction == NULL)
	{
		g_pUserAction = new UserAction;

		if (g_pUserAction == NULL){
			return -1;
		}

		memset(g_pUserAction, 0, sizeof(UserAction));

		InitializeCriticalSection(&g_pUserAction->m_cs);
	}
	return 0;
}

GlsxCommon_API int DeinitUserAction()
{
	if (NULL == g_pUserAction) return 0;

	g_pUserAction->m_bExit = true;

	if (g_pUserAction->m_hFlowThread)
	{
		if (g_pUserAction->nIDTimerEvent)
		{
			KillTimer(NULL, g_pUserAction->nIDTimerEvent);
		}

		SetEvent(g_pUserAction->m_hWaitEvent);

		if(WaitForSingleObject(g_pUserAction->m_hFlowThread, 10000) == WAIT_TIMEOUT)
		{
			TerminateThread(g_pUserAction->m_hFlowThread, 0);
			g_pUserAction->m_hFlowThread = NULL;
		}

		CloseHandle(g_pUserAction->m_hFlowThread);

		CloseHandle(g_pUserAction->m_hWaitEvent);
		g_pUserAction->m_hWaitEvent = NULL;
	}

	::DeleteCriticalSection(&g_pUserAction->m_cs);

	delete g_pUserAction;
	g_pUserAction = NULL;
	return 0;
}

GlsxCommon_API int SubmitUserAction( const std::string& strUserAction )
{
	SafeLock lock(g_pUserAction->m_cs);

	if(strUserAction.empty()) return -1;

	if (g_pUserAction->m_pUserActionData == NULL)
	{
		if (strUserAction.size() > GROW_SIZE)
		{
			g_pUserAction->m_pUserActionData = (char*)malloc(strUserAction.size() + GROW_SIZE);
			//g_pUserAction->m_nDataSize = strUserAction.size();
			g_pUserAction->m_nBufferSize = strUserAction.size() + GROW_SIZE;
		}
		else
		{
			g_pUserAction->m_pUserActionData = (char*)malloc(GROW_SIZE );

			//g_pUserAction->m_nDataSize = strUserAction.size();
			g_pUserAction->m_nBufferSize = GROW_SIZE;
		}

		if (g_pUserAction->m_pUserActionData == NULL)
		{
			printf("malloc user action data buffer error\n");
			return -1;
		}
		memcpy(g_pUserAction->m_pUserActionData, strUserAction.c_str(), strUserAction.size());
		g_pUserAction->m_nDataSize += strUserAction.size();
	}
	else if(g_pUserAction->m_nDataSize + (int)strUserAction.size() > g_pUserAction->m_nBufferSize)
	{
		if (g_pUserAction->m_nDataSize + (int)strUserAction.size() < g_pUserAction->m_nBufferSize + GROW_SIZE)
		{
			g_pUserAction->m_pUserActionData = (char*)realloc(g_pUserAction->m_pUserActionData, 
				g_pUserAction->m_nBufferSize + GROW_SIZE);

			if (g_pUserAction->m_pUserActionData == NULL)
			{
				printf("realloc user action buffer error\n");
				return -1;
			}

			g_pUserAction->m_nDataSize = strUserAction.size();
			g_pUserAction->m_nBufferSize += GROW_SIZE;
		}
		else
		{
			g_pUserAction->m_pUserActionData = (char*)realloc(g_pUserAction->m_pUserActionData,
				g_pUserAction->m_nBufferSize + strUserAction.size() + GROW_SIZE);

			if (g_pUserAction->m_pUserActionData == NULL)
			{
				printf("realloc user action buffer error\n");
				return -1;
			}

			g_pUserAction->m_nDataSize = strUserAction.size();
			g_pUserAction->m_nBufferSize += strUserAction.size() + GROW_SIZE;
		}
		memcpy(g_pUserAction->m_pUserActionData + g_pUserAction->m_nDataSize, 
			strUserAction.c_str(), strUserAction.size());	
	}
	else
	{
		memcpy(g_pUserAction->m_pUserActionData + g_pUserAction->m_nDataSize, 
			strUserAction.c_str(), strUserAction.size());
		g_pUserAction->m_nDataSize = strUserAction.size();
	}


	if (g_pUserAction->m_nDataSize >= GlobalSet::GetSysCfg("SubmitUserActionCache", 524288).asInt())
	{
		if (!g_pUserAction->m_hFlowThread)
		{
			g_pUserAction->m_hWaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
			if(g_pUserAction->m_hWaitEvent == NULL)
			{
				printf("user action  create submit flow event error: %d\n", GetLastError());
				return -1;
			}
			g_pUserAction->m_hFlowThread = CreateThread(NULL, 0, 
				(LPTHREAD_START_ROUTINE)SubmitFlowThread, 0, 0, &g_pUserAction->m_dwThreadId);

			if (g_pUserAction->m_hFlowThread == NULL)
			{
				printf("user action create submit thread error: %d\n", GetLastError());
				return -1;
			}

			g_pUserAction->nIDTimerEvent = SetTimer(NULL, 0, 
				GlobalSet::GetSysCfg("SubmitUserActionTimer", 180000).asInt(), TimerProc);

			if (g_pUserAction->nIDTimerEvent == 0)
			{
				printf("user action  start submit timer error: %d\n", GetLastError());
			}
		}
		SetEvent(g_pUserAction->m_hWaitEvent);
	}
	return 0;
}

END_GLSX_NAMESPACE